package breaker

import (
	"sync"
	"time"
)

// 滑动窗口
type SlidingWindow struct {
	sliding int // 滑动时间范围内
	limit   int // 限定次数
	history map[string][]time.Time
	lock    *sync.Mutex
}

var Sliding = NewSlidingWindow(10, 20)

func NewSlidingWindow(sliding, limit int) *SlidingWindow {
	return &SlidingWindow{
		sliding: sliding,
		limit:   limit,
		history: make(map[string][]time.Time, 0),
		lock:    &sync.Mutex{},
	}
}

// 检查是否可用访问
func (s *SlidingWindow) check(key string) bool {
	s.lock.Lock()
	defer s.lock.Unlock()
	var arr []time.Time
	var ok bool
	now := time.Now()
	// 第一次直接返回
	if arr, ok = s.history[key]; !ok {
		s.history[key] = make([]time.Time, 0, s.limit)
		s.history[key] = append(s.history[key], now)
		return true
	}
	// 累计次数不到上限，直接返回
	if len(arr) < s.limit {
		s.history[key] = append(s.history[key], now)
		return true
	}
	first := arr[0]

	if first.Add(time.Duration(s.sliding) * time.Second).Before(now) {
		s.history[key] = s.history[key][1:]
		s.history[key] = append(s.history[key], now)
		return true
	}

	return false
}
